Lua/Tutorials/Your first gamemode
From JC2-MP Documentation
For this tutorial, we will be creating an extremely simple gamemode called Last Rico Standing. When a game starts, players will spawn inside the dome and be given machine guns. When they die, they will spawn above the dome without weapons. When there is only one person left, they are declared the winner and the game restarts.
It is assumed you have read the Beginner's Tutorial.
Contents
Setup
As before, we will create the lua file in the required directory structure: scripts/MyFirstGamemode/server/LastRicoStanding.lua
Spawn points
First, we need some spawn points. It will be useful to have a way to print our position. This can be done in a few ways, shown below. Either way, you can open server.log to copy their output.
Chat command
function PlayerChat(args) if args.text == "/pos" then print(args.player:GetPosition()) return false end return true end Events:Subscribe("PlayerChat", PlayerChat)
Server console
If you want to play around with the server console, type this: (assuming the module is loaded and you're the only person in the server)
lua MyFirstGamemode print(Player.GetById(0):GetPosition())
Spawning everyone on module load
For our first test, we will make it so when the module is loaded everyone in the server is teleported to a random spawn. You can test it by reloading the module from the console.
spawns = { Vector3(14197.319336, 458.649567, 14382.654297), Vector3(14053.989258, 451.647766, 14313.827148), Vector3(14192.114258, 438.649567, 14359.311523), Vector3(14109.357422, 423.588654, 14350.410156), Vector3(14162.669922, 434.653503, 14290.238281) } function StartGame() for player in Server:GetPlayers() do local randomIndex = math.random(1, #spawns) local spawnPosition = spawns[randomIndex] player:SetPosition(spawnPosition) end end Events:Subscribe("ModuleLoad", StartGame)
spawns is a table used like an array. You can also declare it as an empty table, like spawns = {}, then use table.insert(spawns, Vector3(1, 2, 3)), but either syntax works. You can get the third spawn point by doing local position = spawns[3]. Note that arrays in Lua start at 1, not 0 like most other languages.
You can use Server:GetPlayers() to iterate through every player in the server. It doesn't return a table as you might expect, it returns a fancy iterator function. (You don't need to know that, you can simply use it like above.)
Adding functionality
This script will start a game when you reload the module from the console. Players spawn with machine guns and full health. If someone respawns while a game is in progress, they are teleported to the top of the dome with no weapons. The game won't end, however; we'll fix that later.
spawns = { Vector3(14197.319336, 458.649567, 14382.654297), Vector3(14053.989258, 451.647766, 14313.827148), Vector3(14192.114258, 438.649567, 14359.311523), Vector3(14109.357422, 423.588654, 14350.410156), Vector3(14162.669922, 434.653503, 14290.238281) } deathSpawn = Vector3(14130.737305, 528.022278, 14341.015625) textColor = Color(115, 170, 220) function StartGame() local message = "Starting game with "..Server:GetPlayerCount().." players" Chat:Broadcast("[Last Rico Standing] "..message, textColor) for player in Server:GetPlayers() do local randomIndex = math.random(1, #spawns) local spawnPosition = spawns[randomIndex] player:SetPosition(spawnPosition) -- Give them a machine gun in the primary slot (2). player:ClearInventory() local weapon = Weapon(28) player:GiveWeapon(2, weapon) -- Reset their health to 100%, just in case. player:SetHealth(1) end end function PlayerSpawn(args) -- Remove all of their weapons. args.player:ClearInventory() -- Teleport them to the top of the dome. args.player:SetPosition(deathSpawn) -- Send them a chat message. local message = "[Last Rico Standing] A game in progress, please wait" args.player:SendChatMessage(message, textColor) -- Return false to override the default spawn position set in config.lua. return false end Events:Subscribe("ModuleLoad", StartGame) Events:Subscribe("PlayerSpawn", PlayerSpawn)
Tracking players and declaring a winner
In order to declare a winner, we need to store which players are currently in the game and, when someone dies or quits, check if there's only one left. This is done in our PlayerDeathOrQuit function, called by both the PlayerDeath and PlayerQuit events. Then the game restarts.
spawns = { Vector3(14197.319336, 458.649567, 14382.654297), Vector3(14053.989258, 451.647766, 14313.827148), Vector3(14192.114258, 438.649567, 14359.311523), Vector3(14109.357422, 423.588654, 14350.410156), Vector3(14162.669922, 434.653503, 14290.238281) } deathSpawn = Vector3(14130.737305, 528.022278, 14341.015625) textColor = Color(115, 170, 220) players = {} function StartGame() local message = "Starting game with "..Server:GetPlayerCount().." players" Chat:Broadcast("[Last Rico Standing] "..message, textColor) for player in Server:GetPlayers() do table.insert(players, player) local randomIndex = math.random(1, #spawns) local spawnPosition = spawns[randomIndex] player:SetPosition(spawnPosition) -- Give them a machine gun in the primary slot (2). player:ClearInventory() local weapon = Weapon(28) player:GiveWeapon(2, weapon) -- Reset their health to 100%, just in case. player:SetHealth(1) end end function PlayerSpawn(args) -- If the current game doesn't have enough players and the server has enough -- to create a game, do so. if #players < 2 and Server:GetPlayerCount() >= 2 then StartGame() -- Otherwise, a game is currently running fine and we either joined the server -- or died and respawned. else -- Remove all of their weapons. args.player:ClearInventory() -- Teleport them to the top of the dome. args.player:SetPosition(deathSpawn) -- Send them a chat message. local message = "[Last Rico Standing] A game is in progress, please wait." args.player:SendChatMessage(message, textColor) end -- Return false to override the default spawn position set in config.lua. return false end function PlayerDeathOrQuit(args) -- If they're in the players table, remove them. for index, player in ipairs(players) do if player == args.player then table.remove(players, index) break end end -- If there is only one player left, declare them the winner. if #players == 1 then local message = "[Last Rico Standing] "..players[1]:GetName().." has won the game!" Chat:Broadcast(message , textColor) end end Events:Subscribe("ModuleLoad", StartGame) Events:Subscribe("PlayerSpawn", PlayerSpawn) Events:Subscribe("PlayerDeath", PlayerDeathOrQuit) Events:Subscribe("PlayerQuit", PlayerDeathOrQuit)
Conclusion
Get someone else to test with you and have fun with it. Add a score system to track who has won the most. Create a table of weapons and assign people random ones when a game starts. The possibilities are endless.
As you may have noticed, this is an entirely server-sided script. Adding a client-side component would be extremely powerful; we could add a player counter, scoreboard text, replace the chat messages with text on screen, or add a spectator camera. But client-side scripts will be part of another tutorial.